package com.zzyl.nursing.service.member.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.constant.UserConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.nursing.domain.member.Reservation;
import com.zzyl.nursing.dto.member.ReservationDTO;
import com.zzyl.nursing.mapper.member.MemberReservaMapper;
import com.zzyl.nursing.service.member.IMemberReservationService;
import com.zzyl.nursing.vo.member.TimeCountVO;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 参观预约接口实现类
 *
 * @author makangkang
 * @date 2025/10/22 22:12
 */
@Service
public class IMemberReservationServiceImpl extends ServiceImpl<MemberReservaMapper, Reservation> implements IMemberReservationService {
    /**
     * 查询当天取消预约数量
     *
     * @return
     */
    @Override
    public int cancelledCount() {
        Long userId = UserThreadLocal.get();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 2. 当天00:00:00
        LocalDateTime localDateTimeDayMin = LocalDate.now(ZoneId.of("Asia/Shanghai")).atStartOfDay();
        // 格式化当天0点
        String dayMinStr = localDateTimeDayMin.format(formatter);

        // 3. 当前时间
        LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        // 格式化当前时间
        String nowStr = localDateTime.format(formatter);
        List<Reservation> reservationList = this.lambdaQuery()
                .eq(Reservation::getStatus, 2)
                .between(Reservation::getCreateTime, dayMinStr, nowStr)
                .eq(Reservation::getCreateBy, userId)
                .list();

        // 每个人三次取消机会
        // int conut = UserConstants.TOTAL_NUMBER_CANCELLATIONS_THREE;
        if (CollUtil.isEmpty(reservationList)) {
            // conut = conut - reservationList.size();
            return UserConstants.NUMBER_OF_APPOINTMENTS;
        }
        return reservationList.size();
    }

    /**
     * 查询每个时间段剩余预约次数
     *
     * @param time
     * @return
     */
    @Override
    public List<TimeCountVO> countByTime(Long time) {

        System.out.println(time);
        LocalDateTime localDateTimeStart = Instant.ofEpochMilli(time)
                .atZone(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();

        // 当前时间
        LocalDateTime localDateTimeNow = LocalDateTime.now();
        // 构造返回参数
        List<TimeCountVO> timeCountVOS = new ArrayList<>();
        // 开始八点，结束十八点
        LocalDateTime voTime = localDateTimeStart.plusHours(8);
        LocalDateTime voTimeEnd = localDateTimeStart.plusHours(18);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 循环，从八点开始每三十分钟是一段预约时间，十八点结束
        while (voTime.isBefore(localDateTimeNow)) {
            // 查询该时间剩余几次
            Long count = getByTimeConut(voTime);
            if (count != 0) {
                // 封装数据
                TimeCountVO timeCountVO = getCountVO(formatter, voTime, count);
                timeCountVOS.add(timeCountVO);
            }
            // 循环，每三十分钟是一段预约时间
            voTime = voTime.plusMinutes(30);
            // 超过十八点退出循环
            if (voTime.isAfter(voTimeEnd)) {
                break;
            }
        }

        // 当前时间超过十八点直接结束
        if (localDateTimeNow.isBefore(voTimeEnd)) {
            return timeCountVOS;
        }

        // 当前时间判断,如果不是整点
        int minute = localDateTimeNow.getMinute();

        if (minute == 0 || minute == 30) {
            return timeCountVOS;
        }

        LocalDateTime statrTime = null;
        // 判断时间是在00-30，还是30-60的时间段
        statrTime = getTimePeriod(minute, statrTime, localDateTimeNow);

        Long count = this.lambdaQuery()
                .ne(Reservation::getStatus, UserConstants.RESERVATION_STATUS_CANCEL)
                .between(Reservation::getTime, statrTime, localDateTimeNow)
                .count();
        if (count != 0) {
            // 封装数据
            TimeCountVO timeCountVO = getTimeCountVO(formatter, statrTime, count);
            timeCountVOS.add(timeCountVO);
        }
        return timeCountVOS;
    }

    /**
     * 判断时间是在00-30，还是30-60的时间段
     *
     * @param minute
     * @param statrTime
     * @param localDateTimeNow
     * @return
     */
    private static LocalDateTime getTimePeriod(int minute, LocalDateTime statrTime, LocalDateTime localDateTimeNow) {
        if (minute > 30) {
            statrTime = localDateTimeNow.withMinute(0).withSecond(0).withNano(0);
        }
        if (minute < 30) {
            statrTime = localDateTimeNow.withMinute(30).withSecond(0).withNano(0);
        }
        return statrTime;
    }

    private static TimeCountVO getCountVO(DateTimeFormatter formatter, LocalDateTime voTime, Long count) {
        TimeCountVO timeCountVO = TimeCountVO.builder()
                .time(formatter.format(voTime))
                // 每个时间段最多六个人
                .count((int) (UserConstants.TOTAL_NUMBER_RESERVATIONS_PER_TIME_SLOT_SIX - count))
                .build();
        return timeCountVO;
    }

    /**
     * 封装timeCountVO数据
     *
     * @param formatter
     * @param statrTime
     * @param count
     * @return
     */
    private static TimeCountVO getTimeCountVO(DateTimeFormatter formatter, LocalDateTime statrTime, Long count) {
        TimeCountVO timeCountVO = getCountVO(formatter, statrTime, count);
        return timeCountVO;
    }

    /**
     * 查询该时间剩余几次
     *
     * @param voTime
     * @return
     */
    private Long getByTimeConut(LocalDateTime voTime) {
        Long count = this.lambdaQuery()
                .ne(Reservation::getStatus, UserConstants.RESERVATION_STATUS_CANCEL)
                .eq(Reservation::getTime, voTime)
                .count();
        return count;
    }

    /**
     * 新增预约
     *
     * @param reservationDTO
     * @return
     */
    @Override
    public boolean addReservation(ReservationDTO reservationDTO) {
        Reservation reservation = BeanUtil.toBean(reservationDTO, Reservation.class);

        Long userId = UserThreadLocal.get();
        reservation.setStatus(UserConstants.RESERVATION_STATUS_TO_BE_REPORTED);
        reservation.setCreateBy(userId.toString());
        return this.save(reservation);
    }

    /**
     * 分页查询预约
     *
     * @param reservation
     * @return
     */
    @Override
    public List<Reservation> reservationPage(Reservation reservation) {
        Long userId = UserThreadLocal.get();
        return this.lambdaQuery().eq(Reservation::getCreateBy, userId).orderByDesc(Reservation::getCreateTime).list();
    }

    /**
     * 取消预约
     *
     * @param id
     * @return
     */
    @Override
    public boolean cancelById(Long id) {
        Long userId = UserThreadLocal.get();
        return this.lambdaUpdate()
                .eq(Reservation::getCreateBy, userId)
                .set(Reservation::getStatus, UserConstants.RESERVATION_STATUS_CANCEL)
                .update();
    }

    /**
     * 预约自动过期
     *
     * @return
     */
    @Override
    public boolean memberReservationExpiration() {
        boolean flag = this.lambdaUpdate()
                .eq(Reservation::getStatus, Constants.STATUS_UNPROCESSED)
                .le(Reservation::getTime, DateUtils.getNowDate())
                .set(Reservation::getStatus, Constants.STATUS_EXPIRATION)
                .update();
        return flag ;
    }
}
